﻿///时间：2021年9月
///单位：华南理工大学吴贤铭智能工程
///作者：陈琦
///描述：tcp服务器工具类 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using RoboSensors.Tools;
namespace RoboSensors.Communicate
{
    public class TcpService
    {
        private readonly IPEndPoint endPoint;
        private Socket m_Service;
        private Socket m_CurSocket { get; set; }
        public event EventHandler<String> TcpServiceDataEvent;
        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

        public bool IsHexData { get; set; }

        #region 线程相关
        //接收线程
        private Thread m_ReceiveLoopThread;
        private Queue<String> m_ReceiveQueue = new Queue<string>();
        private String m_ReceiveMessage;

        //连接线程
        private Thread m_ConnectThread;
        bool m_IsConnect { get; set; }

        //发送线程
        private Thread m_SendLoopThread;
        private Queue<String> m_SendQueue = new Queue<string>();
        private bool m_ReadySend { get; set; } = true;
        /// <summary>
        /// 是否根据ready标志位发送数据
        /// </summary>
        public bool WaitSendFuc { get; set; } = true;

        #endregion

        protected virtual void OnTcpServiceData(object sender, String e)
        {
            var handler = TcpServiceDataEvent;
            if (handler != null) handler(this, e);
        }
        public TcpService(string ip, string port)
        {
            IPAddress ipaddress = IPAddress.Parse(ip);
            endPoint = new IPEndPoint(ipaddress, Convert.ToInt32(port));
            m_Service = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public bool Open()
        {
            m_Service.Bind(endPoint);
            m_Service.Listen(10);
            //开辟新线程一直监听客户端的连接
            Thread th = new Thread(Listen);
            th.IsBackground = true;
            th.Start();
            return true;
        }
        private void Listen()
        {
            Socket socketsend;
            m_ReceiveLoopThread = new Thread(ReceiveProcessLoop);
            m_ReceiveLoopThread.IsBackground = true;
            m_ReceiveLoopThread.Start();

            m_SendLoopThread = new Thread(SendDataLoop);
            m_SendLoopThread.IsBackground = true;
            m_SendLoopThread.Start();

            while (true)
            {
                //1，等待客户端的连接，并创建一个用于通信的socket
                socketsend = m_Service.Accept();
                //Console.WriteLine("accept");

                //2.如果有新的连接，让之前连接的线程退出
                m_IsConnect = false;
                Thread.Sleep(1000);

                //3,开辟新的后台线程一直接收客户端发来的消息
                Thread th = new Thread(receive);
                th.IsBackground = true;
                Thread.Sleep(500);
                m_IsConnect = true;
                th.Start(socketsend);
            }
        }
        

        private void receive(object o)  //线程中传递变量必须是object类型
        {
            m_CurSocket = o as Socket;
            
            //将连接的ip和对应的socket存入键值对
            //dicSocket.Add(socketsend.RemoteEndPoint.ToString(), socketsend);

            //将连接的ip和端口号存入combox中
            //comboBox1.Items.Add(socketsend.RemoteEndPoint.ToString());
            int length = 1024 * 1024 * 2;
            byte[] buffer = new byte[length];

            while (m_IsConnect)
            {
                try
                {
                    //接收客户端发来的消息
                    int i = m_CurSocket.Receive(buffer);
                    //Console.WriteLine("receive" + i + "number");
                    //断开连接时接收到的数据长度为0，此时跳出循环
                    if (i == 0)
                        break;
                    string str = Encoding.UTF8.GetString(buffer, 0, i);
                    //Console.WriteLine(str);
                    m_ReceiveQueue.Enqueue(str);
                    //OnTcpServiceData(this,str);
                    Array.Clear(buffer,0, length);
                }
                catch 
                {
                    throw;
                }
            }
            //结束线程的处理
            m_ReceiveQueue.Clear();
            m_SendQueue.Clear();
            m_CurSocket.Disconnect(true);
        }

        /// <summary>
        /// 接收数据处理线程，并将数据发送显示
        /// </summary>
        private void ReceiveProcessLoop()
        {
            while(true)
            {
                Thread.Sleep(10);
                if(m_ReceiveQueue.Count!=0)
                    OnTcpServiceData(this, m_ReceiveQueue.Dequeue());
            }    
        }

        private void SendDataLoop()
        {
            while(true)
            {
                try
                {
                    Thread.Sleep(10);
                    //1,判断是否符合发送条件
                    if (m_SendQueue.Count != 0 && m_ReadySend == true)
                    {
                        //2,发送数据
                        Send(m_SendQueue.Dequeue(), IsHexData);
                        //3，如果开启反馈机制，则将发送标志位清除
                        if (WaitSendFuc == true)
                            m_ReadySend = false;
                    }
                }
                catch (Exception e)
                {
                    continue;
                    throw;
                }
            }
        }


        public void Add2SendLoop(string data)
        {
            m_SendQueue.Enqueue(data);
        }
        private bool Send(string data,bool isHex=false)
        {
            bool result=true;
            byte[] byteArray;
            if (isHex == false)
                byteArray = System.Text.Encoding.Default.GetBytes(data);
            else
                byteArray = data.strToHexByte();
            m_CurSocket.Send(byteArray);
            return result;
        }

        public void SetReadySendFlag(bool isReady)
        {
            m_ReadySend = isReady;
        }
        public void ClearSendList()
        {
            m_SendQueue.Clear();
        }
        public bool Close()
        {
            return true;
        }

        public bool Connect()
        {
            return true;
        }
    }
}
